import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


public class GUI implements ActionListener {

	private JFrame jframe;
	private GraphPanel gpanel;
	private TextPanel tpanel;
	private final int WINDOW_WIDTH = 800;
	private final int WINDOW_HEIGHT = 500;
	private final int GRAPH_WIDTH = 800;
	private final int GRAPH_HEIGHT = 200;
	private final int FEEDBACK_WIDTH = 800;
	private final int FEEDBACK_HEIGHT = 1000;
	private int numberOfProcesses = 4;
	private int timesOfProcesses = 1;
	
	public GUI(){
		this.jframe = new JFrame();
		this.jframe.setTitle("Process Scheduler Simulations");
		this.jframe.setSize(new Dimension(WINDOW_WIDTH,WINDOW_HEIGHT));
		this.jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.jframe.setLayout(new GridLayout(2,1));
		this.jframe.setResizable(true);
		
		
		JMenuBar mb = new JMenuBar();
		JMenu mnuFile = new JMenu("Simulations"); 
		JMenuItem sim1 = new JMenuItem("FIFO");
		sim1.addActionListener(this);
		mnuFile.add(sim1);
		JMenuItem sim2 = new JMenuItem("Non-Preemptive");
		sim2.addActionListener(this);
		mnuFile.add(sim2);
		JMenuItem sim3 = new JMenuItem("Preemptive");
		sim3.addActionListener(this);
		mnuFile.add(sim3);
		JMenuItem sim4 = new JMenuItem("Round Robin");
		sim4.addActionListener(this);
		mnuFile.add(sim4);
		JMenuItem sim5 = new JMenuItem("Feed Back");
		sim5.addActionListener(this);
		mnuFile.add(sim5);
		
		JMenu mnuFile2 = new JMenu("Options"); 
		JMenuItem procNum = new JMenuItem("Set Number of Processes");
		procNum.addActionListener(this);
		mnuFile2.add(procNum);
		JMenuItem procTimes = new JMenuItem("Set Process Repeats");
		procTimes.addActionListener(this);
		mnuFile2.add(procTimes);
		
		
		gpanel = new GraphPanel();
		gpanel.setPreferredSize(new Dimension(GRAPH_WIDTH,GRAPH_HEIGHT));
		gpanel.setBackground(Color.WHITE);
		JScrollPane gpanelScroller = new JScrollPane(gpanel);
		gpanel.scroll = gpanelScroller;
		gpanelScroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		gpanelScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
		
		tpanel = new TextPanel();
		tpanel.setPreferredSize(new Dimension(FEEDBACK_WIDTH,FEEDBACK_HEIGHT));
		tpanel.setBackground(Color.LIGHT_GRAY);
		tpanel.setEditable(false);
		JScrollPane tpanelScroller = new JScrollPane(tpanel);
		tpanelScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
		
		mb.add(mnuFile);
		mb.add(mnuFile2);
		this.jframe.setJMenuBar(mb);
		this.jframe.add(gpanelScroller);
		this.jframe.add(tpanelScroller);
		this.jframe.setVisible(true);
	}
	
	
	
	
	

	public void actionPerformed(ActionEvent e) {
		if(e.getActionCommand().equals("FIFO")) {
			if(tpanel.getSimulator() != null)
				tpanel.getSimulator().stopThread();
			tpanel.clearText();
			tpanel.addToFeedBack("Simulation: First-In-First-Out Scheduler.\n\n" +
			"Processes are Scheduled based on their Arrival Times. First one to arrive executes first until complete and so on.\n");
			Simulation sim = new FIFOSimulator(this.numberOfProcesses,this.timesOfProcesses);
			gpanel.setSimulator(sim);
			tpanel.setSimulator(sim);
			this.jframe.setTitle("Process Scheduler Simulations - FIFO");
			new Thread(sim).start();
		}
		if(e.getActionCommand().equals("Non-Preemptive")) {
			if(tpanel.getSimulator() != null)
				tpanel.getSimulator().stopThread();
			tpanel.clearText();
			tpanel.addToFeedBack("Simulation: (Shortest Service Time) Non-Preemptive Scheduler.\n\n" +
			"Processes are scheduled based on their Service Times. The shortest Service Time is executed first until complete and so on.\n");
			Simulation sim = new NonPreemptiveSimulator(this.numberOfProcesses,this.timesOfProcesses);
			gpanel.setSimulator(sim);
			tpanel.setSimulator(sim);
			this.jframe.setTitle("Process Scheduler Simulations - Non-Preemptive Scheduler.");
			new Thread(sim).start();
		}
		if(e.getActionCommand().equals("Preemptive")) {
			if(tpanel.getSimulator() != null)
				tpanel.getSimulator().stopThread();
			tpanel.clearText();
			tpanel.addToFeedBack("Simulation: (Shortest Remaining Service Time) Preemptive Scheduler.\n\n" +
			"Processes are scheduled based on their Service Times. The shortest Service Time is executed first but can be interupted \nif a shorter service time enters and so on.\n");
			Simulation sim = new PreemptiveSimulator(this.numberOfProcesses,this.timesOfProcesses);
			gpanel.setSimulator(sim);
			tpanel.setSimulator(sim);
			this.jframe.setTitle("Process Scheduler Simulations - Preemptive Scheduler.");
			new Thread(sim).start();
		}
		if(e.getActionCommand().equals("Feed Back")) {
			if(tpanel.getSimulator() != null)
				tpanel.getSimulator().stopThread();
			tpanel.clearText();
			tpanel.addToFeedBack("Simulation: Feed Back Scheduler.\n\n" +
			"Processes are scheduled based on how many times they've been added to the queues. In \n" +
			"this implementation there are four queues. Each queue is first-in first-out(FIFO) and has \n" +
			"a quantum time which is double the quantum of the previous queue. The queue with the smallest \n" +
			"quantum has the highest priority. The quantum is applied as the service time of outgoing \n" +
			"procresses. However, the last queue does not contain a quantum, it instead allows the process \n" +
			"to finish (FCFS).\n");
			Simulation sim = new FeedBackSimulator(this.numberOfProcesses,this.timesOfProcesses);
			gpanel.setSimulator(sim);
			tpanel.setSimulator(sim);
			this.jframe.setTitle("Process Scheduler Simulations - Feed Back Scheduler.");
			new Thread(sim).start();
		}
		if(e.getActionCommand().equals("Round Robin")) {
			if(tpanel.getSimulator() != null)
				tpanel.getSimulator().stopThread();
			tpanel.clearText();
			tpanel.addToFeedBack("Simulation: Round Robin Scheduler.\n\n" +
			"Processes are scheduled based on Quantum and Context Switching.");
			Simulation sim = new RoundRobinSimulator(this.numberOfProcesses,this.timesOfProcesses);
			gpanel.setSimulator(sim);
			tpanel.setSimulator(sim);
			this.jframe.setTitle("Process Scheduler Simulations - Round Robin Scheduler.");
			new Thread(sim).start();
		}
		if(e.getActionCommand().equals("Set Number of Processes")) {
			String str = (String) JOptionPane.showInputDialog(null, "Enter number of processes to run: (Default is 4)", 
					"Simulation Options", JOptionPane.PLAIN_MESSAGE,null,null,"4");
			if(str != null)
				try {
					numberOfProcesses = Integer.parseInt(str);
				}
				catch(NumberFormatException ex) {
					//Do nothing...
					numberOfProcesses = 4;
				}
		}
		if(e.getActionCommand().equals("Set Process Repeats")) {
			String str = (String) JOptionPane.showInputDialog(null, "Times for a Process to repeat: (Default is 1)", 
					"Simulation Options", JOptionPane.PLAIN_MESSAGE,null,null,"1");
			if(str != null)
				try {
					timesOfProcesses = Integer.parseInt(str);
				}
				catch(NumberFormatException ex) {
					//Do nothing...
					timesOfProcesses = 1;
				}
		}
	}
	
	
	
	
	// Startup Driver
	public static void main(String[] args) {
		new GUI();
	}

}






@SuppressWarnings("serial")
class TextPanel extends JTextArea {
	
	private Simulation sim = null;
	private final String FEEDBACK_DEFAULT = "Welcome, please select a Simulation to run from the Simulation Dropdown above.";
	private String feedback = "";
	
	public void setSimulator(Simulation sim) {
		this.sim = sim;
	}
	public Simulation getSimulator()
	{
		return sim;
	}
	public void clearSimulator() {
		this.sim = null;
	}
	
	public void clearText() {
		this.setText("");
		this.feedback = "";
	}
	
	public void addToFeedBack(String newFeedback) {
		feedback = feedback + newFeedback;
	}
	
	public void paint(Graphics g) {
		super.paint(g);
		
		if(sim != null) {
			String tmp = sim.getFeedBackResults();
			if(!tmp.isEmpty()) {
				addToFeedBack(tmp);
			}
			if(!this.getText().equals(feedback))
				this.setText(feedback);
		}
		else
			this.setText(this.FEEDBACK_DEFAULT);
		this.repaint();
	}
	
}

@SuppressWarnings("serial")
class GraphPanel extends JPanel {

	private Simulation sim = null;
	public JScrollPane scroll;
	
	public void setSimulator(Simulation sim) {
		this.sim = sim;
	}
	
	public void clearSimulator() {
		this.sim = null;
	}
	
	public void paint(Graphics g) {
		super.paint(g);
		if(sim != null) {
			this.setPreferredSize(new Dimension(sim.getSimulationWidth()+400,200));
			this.updateUI();
			if(!sim.isComplete())
				scroll.getHorizontalScrollBar().setValue(sim.getSimulationWidth());
			sim.draw(g);
		} else {
		}
		this.repaint();
	}
	
	
}











